import math

def expected_balls_per_box(N: int, M: int) -> float:
    """期望每个盒子中的球数：α = N / M"""
    return N / M

def prob_box_empty(alpha: float) -> float:
    """特定盒子为空的概率：P(empty) ≈ e^(-α)"""
    return math.exp(-alpha)

def expected_throws_to_fill_all_boxes(M: int) -> float:
    """每个盒子至少有1个球时的期望投掷次数：M * H_M ≈ M * ln M"""
    if M <= 0:
        return 0
    harmonic_number_approx = math.log(M) + 0.5772156649  # γ ≈ 0.5772
    return M * harmonic_number_approx

def expected_throws_until_first_collision(M: int) -> float:
    """第一次出现碰撞的期望投掷次数：√(πM/2) ≈ 1.25√M"""
    return math.sqrt(math.pi * M / 2)

# 示例调用
if __name__ == "__main__":
    N = 2000   # 球数
    M = 365  # 盒子数
    alpha = expected_balls_per_box(N, M)

    print(f"球数{N}， 盒子数{M}的分布情况")
    print("-------------------------------------------------------------------------------")
    print(f"1. 每个盒子中球的期望数量: {alpha:.4f}")
    print(f"2. 单个特定盒子为空的概率: {prob_box_empty(alpha):.4f}")
    print(f"3. 所有盒子都至少有1个球的期望投掷次数: {expected_throws_to_fill_all_boxes(M):.2f}")
    print(f"4. 第一次碰撞发生的期望投掷次数: {expected_throws_until_first_collision(M):.2f}")
